#    MythMobile, a Django interface to MythTV for mobile devices
#    Copyright (C) 2011 Andrew Wilkinson (andrewjwilkinson@gmail.com)
#
#     This program is free software; you can redistribute it and/or modify
#     it under the terms of the GNU General Public License as published by
#     the Free Software Foundation; either version 2 of the License, or
#     (at your option) any later version.
#
#     This program is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#     GNU General Public License for more details.
#
#     You should have received a copy of the GNU General Public License along
#     with this program; if not, write to the Free Software Foundation, Inc.,
#     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

import atexit
import json
import os
import struct
import socket
import subprocess
import sys
import threading
import time

from app.backend.main import main as backend_main

import settings

int_size = struct.calcsize("i")

def send_backend_msg(raw_msg, *args):
    c = get_backend_connection()

    msg = json.dumps((raw_msg, ) + args)
    msg_size = struct.pack("i", len(msg))

    thread = threading.currentThread()

    try:
        c.sendall(msg_size + msg)
    except socket.error, e:
        if e.errno == 107: # Transport end point not connected
            delattr(thread, "backend_conn")
            return send_backend_msg(raw_msg, *args)

    if len(thread.remaining_data) < int_size:
        data_size = ""
        while len(data_size) < (int_size - len(thread.remaining_data)):
            new_data = c.recv(4096)
            if len(new_data) == 0:
                return
            data_size += new_data

    thread.remaining_data += data_size[int_size:]
    data_size = data_size[:int_size]

    data_size = struct.unpack("i", data_size)[0]

    if len(thread.remaining_data) < data_size:
        data = ""
        while len(data) < (data_size - len(thread.remaining_data)):
            new_data = c.recv(4096)
            if len(new_data) == 0:
                return
            data += new_data

        thread.remaining_data += data

    data = thread.remaining_data[:data_size]
    thread.remaining_data = thread.remaining_data[data_size:]

    return json.loads(data)

def get_backend_connection(attempt=0):
    if attempt > 1:
        raise SystemError, "Failed to start backend daemon"

    thread = threading.currentThread()

    if not hasattr(thread, "backend_conn"):
        thread.backend_conn = socket.socket(socket.AF_UNIX)
        thread.remaining_data = ""

        try:
            thread.backend_conn.connect(settings.BACKEND_SOCKET_PATH)
        except socket.error, e:
            if e.errno in (2, 111): # 2: File Not Found, 111: Connection refused
                start_backend_daemon()
                get_backend_connection(attempt=attempt+1)
            else:
                raise

    return thread.backend_conn

_mythmobiled = None

def start_backend_daemon():
    global mythmobiled

    _mythmobiled = subprocess.Popen(("mythmobiled %s %s %s %s" % (settings.MYTH_USER, settings.MYTH_PASSWD, settings.MYTH_DB_HOST, settings.MYTH_DB)).split(" "))

    if settings.DEBUG:
        atexit.register(stop_backend_daemon)
    
    time.sleep(1)

def stop_backend_daemon():
    if _mythmobiled is not None:
        _mythmobiled.terminate()
